package diona.search

import net.liftweb.squerylrecord.KeyedRecord
import net.liftweb.record.{MetaRecord, Record}
import org.squeryl.annotations._
import diona.model.PublisherSchema
import net.liftweb.squerylrecord.RecordTypeMode._
import java.util.Calendar
import net.liftweb.record.field._
import net.liftweb.common.Empty
import java.sql.Timestamp

/**
 * User: anton
 * Date: 27.07.11 20:56
 */
class SearchTask extends Record[SearchTask] with KeyedRecord[Long]
{
  override def meta = SearchTask

  @Column(name = "id")
  override val idField = new LongField(this)

  val searchType = new EnumField(this, SearchType)
  val requestId = new LongField(this)

  val requestUrl = new StringField(this, 2048)

  val created = new DateTimeField(this, Calendar.getInstance())
  val processed = new OptionalDateTimeField(this, Empty)
  val resultId = new OptionalLongField(this, Empty)

  val inProgress = new BooleanField(this, false)

  val failed = new BooleanField(this, false)
}

object SearchTask extends SearchTask with MetaRecord[SearchTask]
{
  def table = PublisherSchema.searchTasks

  @volatile var create: (Long, SearchType.Value, String) => SearchTask =
    (requestId, t, url) => {
      inTransaction {
        val task = SearchTask.createRecord
          .searchType(t)
          .requestId(requestId)
          .requestUrl(url)
        table.insert(task)
      }
    }

  @volatile var clear: () => Unit =
    () => {
      inTransaction {
        table.update(t => where(t.inProgress === true) set(t.inProgress := false))
      }
    }

  @volatile var byId: Long => SearchTask = id => {
    inTransaction {
      table.where(_.id === id).single
    }
  }

  @volatile var getNextToProcess: () => SearchTask =
    () => {
      inTransaction {
        val task = from(table)(t =>
          where(t.inProgress === false and (t.resultId isNull) and t.failed === false)
          select(t)
          orderBy(t.created)
          ).single
        task.inProgress(true)
        table.update(task)
        task
      }
    }

  @volatile var markProcessed: (Long, SearchResult) => Unit =
    (taskId, result) => {
      inTransaction {
        table.update(t =>
          where(t.id === taskId)
          set(
            t.resultId := Some(result.id),
            t.processed := Some(new Timestamp(result.date.is.getTimeInMillis)),
            t.inProgress := false
          )
        )
      }
    }

  @volatile var markFailed: (Long) => Unit = taskId => {
    inTransaction {
        table.update(t =>
          where(t.id === taskId)
          set(
            t.inProgress := false,
            t.failed := true
          )
        )
      }
  }
}